package com.z6school.manage.common.aspect;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.z6school.manage.common.annotation.RequiredLog;
import com.z6school.manage.common.util.IPUtils;
import com.z6school.manage.po.Log;
import com.z6school.manage.service.LogService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Date;

//@Order(1)
@Slf4j
@Aspect
@Component
public class LogAspect {

    @Autowired
    private LogService logService;

    @Pointcut("@annotation(com.z6school.manage.common.annotation.RequiredLog)")
    public void logPointCut(){}

    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint jointPoint) throws Throwable{
        long startTime=System.currentTimeMillis();
        //执行目标方法(result为目标方法的执行结果)
        Object result=jointPoint.proceed();
        long endTime=System.currentTimeMillis();
        long totalTime=endTime-startTime;
        log.info("方法执行的总时长为:"+totalTime);
        saveLog(jointPoint,totalTime);
        return result;
    }
    private void saveLog(ProceedingJoinPoint point,
                            long totalTime) throws NoSuchMethodException, SecurityException, JsonProcessingException {
        //1.获取日志信息
        MethodSignature ms= (MethodSignature)point.getSignature();
        Class<?> targetClass=point.getTarget().getClass();
        String className=targetClass.getName();
        //获取接口声明的方法
        String methodName=ms.getMethod().getName();
        Class<?>[] parameterTypes=ms.getMethod().getParameterTypes();
        //获取目标对象方法(AOP版本不同,可能获取方法对象方式也不同)
        Method targetMethod=targetClass.getDeclaredMethod(
                methodName,parameterTypes);
        //获取用户名,学完shiro再进行自定义实现,没有就先给固定值
        //String username=ShiroUtils.getPrincipal().getUsername();
        String username = "admin";
        //获取方法参数
        Object[] paramsObj=point.getArgs();
        System.out.println("paramsObj="+paramsObj);
        //将参数转换为字符串
        String params=new ObjectMapper()
                .writeValueAsString(paramsObj);
        //2.封装日志信息
        Log log=new Log();
        log.setUsername(username);//登陆的用户
        //假如目标方法对象上有注解,我们获取注解定义的操作值
        RequiredLog requestLog=
                targetMethod.getDeclaredAnnotation(RequiredLog.class);
        if(requestLog!=null){
            log.setOperation(requestLog.operation());
        }
        log.setMethod(className+"."+methodName).setParams(params).setIp(IPUtils.getIpAddr()).setTime((int)totalTime).setCreatedTime(new Date());
        //3.保存日志信息
        logService.saveObject(log);
    }
}
